package com.lancer.cloud.gateway.router;

import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.lancer.cloud.common.constants.CharacterConstants;
import com.lancer.cloud.gateway.entity.ZuulRouteVO;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * 动态路由
 *
 * @author caijinbang
 * @date 2019-06-16 13:06
 */
@Slf4j
public abstract class ZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    private ZuulProperties properties;

    private JdbcTemplate jdbcTemplate;

    public ZuulRouteLocator(String servletPath, ZuulProperties properties,
        JdbcTemplate jdbcTemplate) {
        super(servletPath, properties);
        this.properties = properties;
        this.jdbcTemplate = jdbcTemplate;
        log.info("servletPath:{}", servletPath);
    }

    /**
     * 刷新路由配置
     */
    @Override
    public void refresh() {
        doRefresh();
    }

    /**
     *
     */
    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = Maps.newLinkedHashMap();
        //从application.properties中加载路由信息
        routesMap.putAll(super.locateRoutes());
        //从db中加载路由信息
        routesMap.putAll(locateRoutesFromDB());
        //优化一下配置
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    /**
     * 从数据库读取zuul路由规则
     *
     * @return 路由
     */
    private LinkedHashMap<String, ZuulProperties.ZuulRoute> locateRoutesFromDB() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> zuulRoutes = new LinkedHashMap<>();
        String sql = "SELECT * FROM sys_zuul_route WHERE del_flag = 0";
        List<ZuulRouteVO> zuulRouteVos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ZuulRouteVO.class));
        for (ZuulRouteVO route : zuulRouteVos) {
            // 为空跳过
            if (Strings.isNullOrEmpty(route.getPath()) && Strings.isNullOrEmpty(route.getUrl())) {
                continue;
            }
            ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
            try {
                zuulRoute.setId(route.getServiceId());
                zuulRoute.setPath(route.getPath());
                zuulRoute.setServiceId(route.getServiceId());
                zuulRoute.setRetryable(Objects.equals("0", route.getRetryable()) ? Boolean.FALSE : Boolean.TRUE);
                zuulRoute.setStripPrefix(Objects.equals("0", route.getStripPrefix()) ? Boolean.FALSE : Boolean.TRUE);
                zuulRoute.setUrl(route.getUrl());
                //敏感请求头处理
                if (!StringUtils.isEmpty(route.getSensitiveHeadersList())) {
                    List<String> sensitiveHeadersList = Arrays.asList(route.getSensitiveHeadersList().split(CharacterConstants.COMMA));
                    if (!CollectionUtils.isEmpty(sensitiveHeadersList)) {
                        Set<String> sensitiveHeaderSet = Sets.newHashSet();
                        sensitiveHeadersList.addAll(sensitiveHeaderSet);
                        zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
                        zuulRoute.setCustomSensitiveHeaders(true);
                    }
                } else {
                    // 处理默认情况 不能转发header中的authentication
                    Set<String> sensitiveHeaderSet = Sets.newHashSet();
                    zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
                    zuulRoute.setCustomSensitiveHeaders(true);
                }
            } catch (Exception e) {
                log.error("从数据库加载路由配置异常", e);
            }
            log.debug("添加数据库自定义的路由配置,path：{}，serviceId:{}", zuulRoute.getPath(), zuulRoute.getServiceId());
            zuulRoutes.put(zuulRoute.getPath(), zuulRoute);
        }
        return zuulRoutes;
    }
}
